package com.leyou.order.service;

import com.leyou.common.auth.pojo.UserHolder;
import com.leyou.common.constant.LyConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.entity.Sku;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.dto.OrderStatusEnum;
import com.leyou.order.dto.OrderVO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PayHelper payHelper;

    public Long saveOrder(OrderDTO orderDTO) {
        try {
            //保存订单
            //初始化一个订单对象
            Order order = new Order();
            //提供订单id
            long orderId = idWorker.nextId();
            //获取用户id
            Long userId = UserHolder.getUserId();
            //计算订单总金额 [每个sku的价格 乘以 数量 最后全部相加]
            //获取提交的购物车数据
            List<CartDTO> carts = orderDTO.getCarts();
            //将列表结构的集合转成map结构集合  其中 key-->skuId   value-->num
            Map<Long, Integer> cartsMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
            //通过购物车的集合获取到sku的id的集合
            List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
            //通过sku的id的集合查询出Sku对象的集合
            List<Sku> skus = itemClient.findSkusByIds(skuIds);
            //用流计算总金额
            long totalFee = skus.stream().mapToLong(sku -> sku.getPrice() * cartsMap.get(sku.getId())).sum();
            //给订单对象的属性赋值
            order.setOrderId(orderId);
            order.setUserId(userId);
            order.setStatus(OrderStatusEnum.INIT.value());
            order.setSourceType(2);
            order.setInvoiceType(0);
            order.setPaymentType(orderDTO.getPaymentType());
            order.setPostFee(0L);
            order.setTotalFee(totalFee); //订单总金额
            order.setActualFee(1L); //实付金额
            //保存订单
            orderMapper.insertSelective(order);

            //保存订单详情
            //初始化一个订单详情集合
            List<OrderDetail> orderDetails = new ArrayList<>();
            //遍历Sku对象集合
            skus.forEach(sku -> {
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setId(idWorker.nextId());
                orderDetail.setOrderId(orderId);
                orderDetail.setSkuId(sku.getId());
                orderDetail.setTitle(sku.getTitle());
                orderDetail.setPrice(sku.getPrice());
                orderDetail.setOwnSpec(sku.getOwnSpec());
                orderDetail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
                orderDetail.setNum(cartsMap.get(sku.getId()));
                orderDetail.setCreateTime(new Date());
                orderDetail.setUpdateTime(new Date());
                orderDetails.add(orderDetail);
            });
            //批量保存订单详情
            detailMapper.insertList(orderDetails);

            //保存物流信息
            //获取用户的物流信息
            AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUserId(), orderDTO.getAddressId());
            //将物流dto对象转成物流对象
            OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
            //给物流对象的id赋值
            orderLogistics.setOrderId(orderId);
            //保存物流对象
            logisticsMapper.insertSelective(orderLogistics);

            //减库存
            itemClient.minusStock(cartsMap);

            return orderId;
        }catch (Exception e){
            e.printStackTrace();
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

    }

    public OrderVO findOrderVoById(Long id) {
        //查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        //判空
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //将Order对象转成OrderVO对象
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        //查询订单详情列表
        OrderDetail record = new OrderDetail();
        record.setOrderId(order.getOrderId());
        List<OrderDetail> orderDetails = detailMapper.select(record);
        if(CollectionUtils.isEmpty(orderDetails)){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //给订单对象的订单详情属性设置值
        orderVO.setDetailList(orderDetails);
        //查询物流信息
        OrderLogistics orderLogistics = logisticsMapper.selectByPrimaryKey(id);
        //判空
        if(orderLogistics==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //给订单对象的物流信息赋值
        orderVO.setLogistics(orderLogistics);
        return orderVO;
    }

    public String getPayUrl(Long orderId) {
        //得到redis中存储的当前订单的支付链接的key
        String payUrlKey = LyConstants.PAY_URL_PRE+orderId;
        //从redis中获取当前订单的支付链接
        String payUrl = redisTemplate.opsForValue().get(payUrlKey);
        //判断是否获取到
        if(!StringUtils.isEmpty(payUrl)){
            return payUrl;
        }
        //通过订单号查询订单信息
        Order order = orderMapper.selectByPrimaryKey(orderId);
        //判空
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //判断订单是否已经支付
        if(order.getStatus()!=OrderStatusEnum.INIT.value()){
            log.error("【获取微信支付链接出错！】订单已支付！");
            throw new LyException(501, "订单已支付！");
        }
        //调用获取支付链接的工具类获取支付链接
        payUrl = payHelper.getPayUrl(orderId, order.getActualFee());
        //将获取到的支付链接放入redis
        redisTemplate.opsForValue().set(payUrlKey, payUrl, 2, TimeUnit.HOURS);
        return payUrl;
    }

    public Integer findOrderStatus(Long id) {
        Order order = orderMapper.selectByPrimaryKey(id);
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }

    /**
     * 主要是判断支付金额与本地订单的实付金额是否一致，如果一致要修改订单状态，然后告知微信，收到通知！
     * @param wxParam
     * @return
     */
    public Map<String, String> wxNotify(Map<String, String> wxParam) {
        log.info("【微信回调通知】开始！");
        //判断通信标识和业务标识
        payHelper.checkResult(wxParam);
        //获取商户订单号
        Long orderId = Long.valueOf(wxParam.get("out_trade_no"));
        //获取支付金额
        Long totalFee = Long.valueOf(wxParam.get("total_fee"));
        //根据订单号查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        //判空
        if(order==null){
            log.error("【微信回调通知】失败！订单不存在！");
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        if(order.getStatus()!=OrderStatusEnum.INIT.value()){
            log.error("【微信回调通知】失败！订单已经支付！");
            throw new LyException(501, "订单已经支付！");
        }
        //比对金额
        if(!order.getActualFee().equals(totalFee)){
            log.error("【微信回调通知】失败！支付金额不对！");
            throw new LyException(501, "支付金额不对！");
        }
        //修改订单状态
        Order record = new Order();
        record.setOrderId(orderId);
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        int count = orderMapper.updateByPrimaryKeySelective(record);
        if(count!=1){
            log.error("【微信回调通知】失败！本地跟新订单状态异常！");
        }
        //封装通知微信的结果
        Map<String, String> result = new HashMap<>();
        result.put("return_code", "SUCCESS");
        result.put("return_msg", "OK");
        return result;
    }
}
